ã·ãŒã ã¬ã¹ã§å®å šãªèªèšŒãå®çŸãã¯ã³ã¿ãããµã€ã³ã€ã³ããã§ãã¬ãŒã·ã§ã³ãã°ã€ã³ããã¹ã¯ãŒãã¬ã¹ãããŒã®ããã®Credential Management APIã培åºè§£èª¬ã
ãµã€ã³ã€ã³ã®å¹çåïŒããã³ããšã³ãCredential Management APIã®åŸ¹åºè§£èª¬
ããžã¿ã«ç€ŸäŒã«ãããŠããµã€ã³ã€ã³ãã©ãŒã ã¯æãéèŠã§ãããªãããæãé£ãããŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ã®äžã€ã§ããããã¯ã¢ããªã±ãŒã·ã§ã³ãžã®å ¥ãå£ã§ãããšåæã«ã倧ããªæ©æŠïŒããªã¯ã·ã§ã³ïŒãçããã€ã³ãã§ããããŸãããŠãŒã¶ãŒã¯ãã¹ã¯ãŒããå¿ãããŠãŒã¶ãŒåãã¿ã€ããã¹ããäžæºããã«ãŒãããµãŒãã¹ãæŸæ£ããŸããéçºè ã«ãšã£ãŠãèªèšŒã®ç®¡çã¯ãã·ãŒã ã¬ã¹ãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ïŒUXïŒã®æäŸãšå ç¢ãªã»ãã¥ãªãã£ã®ç¢ºä¿ãšã®éã®è€éãªãã©ã³ã¹èª¿æŽã§ãã
é·å¹Žããã®ããã»ã¹ã¯ãã©ãŠã¶ã®èªåå ¥åããµãŒãããŒãã£ã®ãã¹ã¯ãŒããããŒãžã£ãŒã«ãã£ãŠæ¯æŽãããŠããŸããããããã¯äŸ¿å©ã§ããããŠã§ãã¢ããªã±ãŒã·ã§ã³ãããããšå¯Ÿè©±ããããã®æšæºåãããããã°ã©ã çãªæ¹æ³ãæ¬ ããŠããããšããããããŸããããã§ç»å Žããã®ãCredential Management APIïŒCredMan APIïŒã§ããããã¯ããŠã§ããµã€ãããŠãŒã¶ãŒèªèšŒæ å ±ã管çããããã®ãã©ãŠã¶ãã€ãã£ãã®ã¡ã«ããºã ãæäŸããW3Cæšæºã§ãããã¯ã³ã¿ãããµã€ã³ã€ã³ãèªåèªèšŒããããŠãã¹ã¯ãŒãã¬ã¹ã®æªæ¥ãžã®ããã¹ã ãŒãºãªç§»è¡ãžã®éãéããŸãã
ãã®åŸ¹åºè§£èª¬ã§ã¯ãCredential Management APIã«ã€ããŠç¥ãã¹ãããšã®ãã¹ãŠãã¬ã€ãããŸãããããäœã§ãããããªãçŸä»£ã®ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠã²ãŒã ãã§ã³ãžã£ãŒãªã®ãããããŠèªèšŒãããŒãé©åœçã«å€ããããã«æ®µéçã«å®è£ ããæ¹æ³ãæ¢ã£ãŠãããŸãã
Credential Management APIãšã¯äœãïŒ
Credential Management APIã¯ããŠã§ããµã€ããšãã©ãŠã¶ã®èªèšŒæ å ±ã¹ãã¢ãšã®éã®å¯Ÿè©±ãæšæºåãããJavaScriptããŒã¹ã®ãã©ãŠã¶APIã§ããããã¯ãã¢ããªã±ãŒã·ã§ã³ãããã°ã©ã çã«ãµã€ã³ã€ã³çšã®èªèšŒæ å ±ãèŠæ±ããããç»é²åŸã«ãã©ãŠã¶ã«èªèšŒæ å ±ã®ä¿åãäŸé Œãããããããšãããã¹ãŠãŠãŒã¶ãŒã®æç¢ºãªåæã®ããšã§å¯èœã«ããå ¬åŒãªéä¿¡ãã£ãã«ãšèããããšãã§ããŸãã
ããã¯æœè±¡åã¬ã€ã€ãŒãšããŠæ©èœããéçºè ãããŸããŸãªçš®é¡ã®èªèšŒæ å ±ãã©ã®ããã«æ±ãããç°¡çŽ åããŸããçã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒãã®ãã£ãŒã«ããåã«æ±ãã®ã§ã¯ãªããAPIã¯æ§é åãããèªèšŒæ å ±ãªããžã§ã¯ããæ±ããŸããäž»ã«3ã€ã®ã¿ã€ãããµããŒãããŠããŸãïŒ
- PasswordCredential: åŸæ¥ã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒãã®çµã¿åããã
- FederatedCredential: GoogleãFacebookããŸãã¯äŒæ¥ã®SAMLãããã€ããŒãªã©ã®ãã§ãã¬ãŒã·ã§ã³IDãããã€ããŒããã®IDã¢ãµãŒã·ã§ã³ã
- PublicKeyCredential: WebAuthnæšæºãä»ãããã¹ã¯ãŒãã¬ã¹èªèšŒã«äœ¿çšãããã匷åã§ãã£ãã·ã³ã°èæ§ã®ããèªèšŒæ å ±ã¿ã€ããããã«ã¯ãçäœèªèšŒïŒæçŽãé¡èªèšŒïŒãããŒããŠã§ã¢ã»ãã¥ãªãã£ããŒããã°ãã°é¢ãããŸãã
`navigator.credentials`ãªããžã§ã¯ããšããåäžã®çµ±äžãããã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããããšã§ããã®APIã¯ãåºç€ãšãªãèªèšŒæ å ±ã®ã¿ã€ãã«é¢ä¿ãªããéåžžã«ãŠãŒã¶ãŒãã¬ã³ããªãŒã§å®å šãªãæŽç·ŽãããèªèšŒãããŒãæ§ç¯ããããšãå¯èœã«ããŸãã
ããªãã®ã¢ããªã±ãŒã·ã§ã³ã«Credential Management APIãå¿ èŠãªçç±
CredMan APIã®çµ±åã¯ãåã«ææ°æè¡ãæ¡çšããããšã ãã§ã¯ãããŸãããããã¯ããŠãŒã¶ãŒãšéçºããŒã ã«å ·äœçãªå©çãããããããšã§ãã
1. ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ïŒUXïŒã®ææ¬çãªåäž
ããã¯ééããªãæå€§ã®å©ç¹ã§ããAPIã¯ãµã€ã³ã€ã³ã®æ©æŠã«çŽæ¥åãçµã¿ãŸãã
- ã¯ã³ã¿ãããµã€ã³ã€ã³: å蚪ãŠãŒã¶ãŒã«å¯ŸããŠããã©ãŠã¶ã¯ã¢ã«ãŠã³ãéžæUIã衚瀺ããäžåºŠããã¹ã¯ãŒããå ¥åããããšãªããã·ã³ã°ã«ã¿ãããŸãã¯ã¯ãªãã¯ã§ãµã€ã³ã€ã³ã§ããããã«ããŸãã
- èªåãµã€ã³ã€ã³: å蚪ãŠãŒã¶ãŒããµã€ãã蚪ãããšããã«èªåçã«ãµã€ã³ã€ã³ããããã«APIãèšå®ã§ãããã€ãã£ãã¢ãã€ã«ã¢ããªã®ãããªã·ãŒã ã¬ã¹ãªäœéšãæäŸããŸããããã¯æç€ºçã«ãã°ã¢ãŠãããŠããªããŠãŒã¶ãŒã«æé©ã§ãã
- ãã©ãŒã é¢è±ã®åæž: ãµã€ã³ã€ã³ãšç»é²ããã»ã¹ãç°¡çŽ åããããšã§ããŠãŒã¶ãŒã®èªç¥çè² è·ã軜æžããå®äºçã®åäžãšãŠãŒã¶ãŒç¶æçã®æ¹åã«ã€ãªãããŸãã
- çµ±äžããããã§ãã¬ãŒã·ã§ã³ãã°ã€ã³: ãïœã§ãµã€ã³ã€ã³ãã®äœéšãå¹çåããŸãããããã¢ããããªãã€ã¬ã¯ããæåã§ç®¡çãã代ããã«ãAPIã¯ãã§ãã¬ãŒã·ã§ã³IDãèŠæ±ããæšæºçãªæ¹æ³ãæäŸãããã©ãŠã¶ãããã仲ä»ã§ããŸãã
2. ã»ãã¥ãªãã£æ å¢ã®æ¹å
UXãåäžãããªãããAPIã¯ã»ãã¥ãªãã£é¢ã§ãå€§å¹ ãªæ¹åããããããŸãã
- ãã£ãã·ã³ã°èæ§: APIã«ãã£ãŠç®¡çãããèªèšŒæ å ±ã¯ãç¹å®ã®ãªãªãžã³ïŒãããã³ã«ããã¡ã€ã³ãããŒãïŒã«çŽä»ããããŸããããã«ããããã©ãŠã¶ã¯`yourbank.com`çšã®èªèšŒæ å ±ã`your-bank.com`ã®ãããªãã£ãã·ã³ã°ãµã€ãã§è£å®ææ¡ããããšããªããªããŸããããã¯åŸæ¥ã®ãã¹ã¯ãŒãèªåå ¥åãè匱ãšãªãããäžè¬çãªæ»æãã¯ãã«ã§ãã
- ãã¹ã¯ãŒãã¬ã¹ãžã®ã²ãŒããŠã§ã€: ãã®APIã¯WebAuthnïŒ`PublicKeyCredential`ïŒã®æå®ããããšã³ããªãã€ã³ãã§ãããã¹ã¯ãŒãããŒã¹ã®ãã°ã€ã³ã«ãããæ¡çšããããšã§ãå°æ¥çã«ãã¹ã¯ãŒãã¬ã¹ãçäœèªèšŒããŸãã¯ããŒããŠã§ã¢ããŒèªèšŒãç°¡åã«è¿œå ããããã®åºç€ãæ§ç¯ããããšã«ãªããŸãã
- æšæºåãšæ€èšŒ: æ©å¯æ§ã®é«ãèªèšŒæ å ±ãæ±ãããã®ããã©ãŠã¶ã«ãã£ãŠæ€èšŒãããæšæºåãããã€ã³ã¿ãŒãã§ãŒã¹ãæäŸãããŠãŒã¶ãŒããŒã¿ãæŒæŽ©ãããå¯èœæ§ã®ããå®è£ ãšã©ãŒã®ãªã¹ã¯ãäœæžããŸãã
3. ã·ã³ãã«ã§å°æ¥æ§ã®ããéçº
ãã®APIã¯ãè€éãªèªèšŒããžãã¯ãç°¡çŽ åãããã¯ãªãŒã³ã§PromiseããŒã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããŸãã
- è€éãã®æœè±¡å: èªèšŒæ å ±ãã©ãã«ä¿åãããŠãããïŒãã©ãŠã¶ã®å éšãããŒãžã£ãŒãOSã¬ãã«ã®ããŒãã§ãŒã³ãªã©ïŒã®å ·äœçãªè©³çŽ°ãæ°ã«ããå¿ èŠã¯ãããŸããããªã¯ãšã¹ããè¡ãã ãã§ãæ®ãã¯ãã©ãŠã¶ãåŠçããŸãã
- ããã¯ãªãŒã³ãªã³ãŒãããŒã¹: ãµã€ã³ã€ã³ãšç»é²ã®ããã®ç ©éãªãã©ãŒã ã¹ã¯ã¬ã€ãã³ã°ãã€ãã³ãåŠçããžãã¯ããè±åŽããã®ã«åœ¹ç«ã¡ãããä¿å®ããããã³ãŒãã«ã€ãªãããŸãã
- åæ¹äºææ§: æ°ããèªèšŒæ¹æ³ãç»å ŽããŠãããããã¯Credential Management APIãã¬ãŒã ã¯ãŒã¯ã«çµ±åã§ããŸãããã®æšæºã«åºã¥ããŠæ§ç¯ããããšã§ãããªãã®ã¢ããªã±ãŒã·ã§ã³ã¯ãŠã§ãã¢ã€ãã³ãã£ãã£ã®æªæ¥ã«ããè¯ãåããããšãã§ããŸãã
ã³ã¢ã³ã³ã»ãããšAPIã®åŸ¹åºè§£èª¬
APIå šäœã¯`navigator.credentials`ãªããžã§ã¯ããäžå¿ã«å±éãããããã¯èªèšŒæ å ±ã管çããããã®äžé£ã®ã¡ãœãããå ¬éããŸããæãéèŠãªãã®ãåè§£ããŠã¿ãŸãããã
`get()`ã¡ãœããïŒãµã€ã³ã€ã³ã®ããã®èªèšŒæ å ±ååŸ
ããã¯ãµã€ã³ã€ã³ããã»ã¹ã®äž»åã§ãã`navigator.credentials.get()`ã䜿çšããŠããŠãŒã¶ãŒãèªèšŒããããã«äœ¿çšã§ããèªèšŒæ å ±ããã©ãŠã¶ã«èŠæ±ããŸããããã¯ã`Credential`ãªããžã§ã¯ãããŸãã¯èªèšŒæ å ±ãèŠã€ãããªãã£ãããŠãŒã¶ãŒããªã¯ãšã¹ãããã£ã³ã»ã«ããå Žåã¯`null`ã§è§£æ±ºãããPromiseãè¿ããŸãã
`get()`ã®åã¯ãã®èšå®ãªããžã§ã¯ãã«ãããŸããéèŠãªããããã£ã¯`mediation`ã§ãããã¯ãŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ã®ã¬ãã«ãå¶åŸ¡ããŸãïŒ
mediation: 'silent': ããã¯èªåãµã€ã³ã€ã³ãããŒçšã§ãããŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ãªãã§èªèšŒæ å ±ãååŸããããã«ãã©ãŠã¶ã«æç€ºããŸããUIããã³ãããå¿ èŠãªå ŽåïŒäŸïŒãŠãŒã¶ãŒãè€æ°ã®ã¢ã«ãŠã³ãã«ãã°ã€ã³ããŠããå ŽåïŒããªã¯ãšã¹ãã¯ãµã€ã¬ã³ãã«å€±æããŸããããã¯ãããŒãžèªã¿èŸŒã¿æã«ãŠãŒã¶ãŒãã¢ã¯ãã£ããªã»ãã·ã§ã³ãæã£ãŠãããã©ããã確èªããã®ã«çæ³çã§ããmediation: 'optional': ãããããã©ã«ãã§ããå¿ èŠã«å¿ããŠããã©ãŠã¶ã¯ã¢ã«ãŠã³ãéžæãªã©ã®UIã衚瀺ããããšããããŸãããŠãŒã¶ãŒãéå§ãããµã€ã³ã€ã³ãã¿ã³ã«æé©ã§ããmediation: 'required': ããã¯ãã©ãŠã¶ã«åžžã«UIã衚瀺ãããããšã匷å¶ããŸããããã¯ããŠãŒã¶ãŒãæç€ºçã«åèªèšŒãããã»ãã¥ãªãã£ã«ææãªã³ã³ããã¹ãã§åœ¹ç«ã¡ãŸãã
äŸïŒãã¹ã¯ãŒãèªèšŒæ å ±ã®ãªã¯ãšã¹ã
async function signInUser() {
try {
const cred = await navigator.credentials.get({
password: true,
mediation: 'optional' // or 'silent' for auto-login
});
if (cred) {
// A credential object was returned
// Send it to the server for verification
await serverLogin(cred);
} else {
// User cancelled the prompt or no credentials available
// Fallback to manual form entry
}
} catch (e) {
console.error('Error getting credential:', e);
}
}
`create()`ãš`store()`ã¡ãœããïŒèªèšŒæ å ±ã®ä¿å
ãŠãŒã¶ãŒãç»é²ãŸãã¯ãã¹ã¯ãŒããæŽæ°ããåŸããã®æ°ããæ å ±ãä¿åãããããã©ãŠã¶ã«äŒããæ¹æ³ãå¿ èŠã§ããAPIã¯ããã«å¯ŸããŠ2ã€ã®ã¡ãœãããæäŸããŸãã
`navigator.credentials.create()`ã¯ãäž»ã«æ°ããèªèšŒæ å ±ãçæããããã«äœ¿çšãããŸããç¹ã«ãããŒãã¢ãäœæããã`PublicKeyCredential`ïŒWebAuthnïŒã®å Žåã§ãããã¹ã¯ãŒãã®å Žåã¯ã`PasswordCredential`ãªããžã§ã¯ããæ§ç¯ããããã`navigator.credentials.store()`ã«æž¡ãããšãã§ããŸãã
`navigator.credentials.store()`ã¯èªèšŒæ å ±ãªããžã§ã¯ããåãåãããã©ãŠã¶ã«ãããä¿åããããä¿ããŸããããã¯ãç»é²æååŸã«ãŠãŒã¶ãŒå/ãã¹ã¯ãŒãã®è©³çްãä¿åããæãäžè¬çãªæ¹æ³ã§ãã
äŸïŒç»é²åŸã«æ°ãããã¹ã¯ãŒãèªèšŒæ å ±ãä¿åãã
async function handleRegistration(form) {
// 1. Submit form data to your server
const response = await serverRegister(form);
// 2. If registration is successful, create a credential object
if (response.ok) {
const newCredential = new PasswordCredential({
id: form.username.value,
password: form.password.value,
name: form.displayName.value,
iconURL: 'https://example.com/path/to/icon.png'
});
// 3. Ask the browser to store it
try {
await navigator.credentials.store(newCredential);
console.log('Credential stored successfully!');
} catch (e) {
console.error('Error storing credential:', e);
}
}
}
`preventSilentAccess()`ã¡ãœããïŒãµã€ã³ã¢ãŠãã®åŠç
ãã®ã¡ãœããã¯ãå®å šã§å®å šãªèªèšŒã©ã€ããµã€ã¯ã«ã«ãšã£ãŠéåžžã«éèŠã§ãããŠãŒã¶ãŒãã¢ããªã±ãŒã·ã§ã³ããæç€ºçã«ãµã€ã³ã¢ãŠãããå Žåãæ¬¡åã®èšªåæã«`mediation: 'silent'`ãããŒãèªåçã«ãµã€ã³ã€ã³ãçŽãã®ãé²ããããšèããŸãã
`navigator.credentials.preventSilentAccess()`ãåŒã³åºããšããŠãŒã¶ãŒã次ã«ïŒãµã€ã¬ã³ãã§ã¯ãªãïŒãŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ã䌎ã£ãŠãµã€ã³ã€ã³ãããŸã§ããµã€ã¬ã³ããªèªåãµã€ã³ã€ã³æ©èœãç¡å¹ã«ãªããŸããããã¯ãåçŽã§äžåºŠåŒã³åºãã°ããPromiseã§ãã
äŸïŒãµã€ã³ã¢ãŠããããŒ
async function handleSignOut() {
// 1. Invalidate the session on your server
await serverLogout();
// 2. Prevent silent re-login on the client
if (navigator.credentials && navigator.credentials.preventSilentAccess) {
await navigator.credentials.preventSilentAccess();
}
// 3. Redirect to the homepage or sign-in page
window.location.href = '/';
}
å®è·µçãªå®è£ ïŒå®å šãªèªèšŒãããŒã®æ§ç¯
ãããã®ã³ã³ã»ãããçµã³ã€ããŠãå ç¢ãªãšã³ãããŒãšã³ãã®èªèšŒäœéšãæ§ç¯ããŸãããã
ã¹ããã1ïŒæ©èœæ€åº
ãŸããAPIã䜿çšããããšããåã«ããã©ãŠã¶ãããããµããŒãããŠããããåžžã«ç¢ºèªããŠãã ãããããã«ãããå€ããã©ãŠã¶ã§ã®åªé ãªæ©èœäœäžïŒgraceful degradationïŒãä¿èšŒãããŸãã
const isCredManApiSupported = ('credentials' in navigator);
if (isCredManApiSupported) {
// Proceed with API-based flows
} else {
// Fallback to traditional form logic
}
ã¹ããã2ïŒèªåãµã€ã³ã€ã³ãããŒïŒããŒãžèªã¿èŸŒã¿æïŒ
ãŠãŒã¶ãŒãããªãã®ãµã€ãã蚪ãããšãããã©ãŠã¶ã®èªèšŒæ å ±ãããŒãžã£ãŒã«æ¢åã®ã»ãã·ã§ã³ãä¿åãããŠããã°ãèªåçã«ãµã€ã³ã€ã³ã詊ã¿ãããšãã§ããŸãã
window.addEventListener('load', async () => {
if (!isCredManApiSupported) return;
try {
const cred = await navigator.credentials.get({
password: true,
mediation: 'silent'
});
if (cred) {
console.log('Silent sign-in successful. Verifying with server...');
// Send the credential to your backend to validate and create a session
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: cred.id, password: cred.password })
});
if (response.ok) {
// Update UI to reflect logged-in state
updateUIAfterLogin();
}
}
// If 'cred' is null, do nothing. The user will see the standard sign-in page.
} catch (e) {
console.info('Silent get() failed. This is expected if user is signed out.', e);
}
});
ã¹ããã3ïŒãŠãŒã¶ãŒãéå§ãããµã€ã³ã€ã³ãããŒïŒãã¿ã³ã¯ãªãã¯æïŒ
ãŠãŒã¶ãŒãããµã€ã³ã€ã³ããã¿ã³ãã¯ãªãã¯ãããšãã€ã³ã¿ã©ã¯ãã£ããªãããŒãããªã¬ãŒãããŸãã
const signInButton = document.getElementById('signin-button');
signInButton.addEventListener('click', async () => {
if (!isCredManApiSupported) {
// Let the traditional form submission handle it
return;
}
try {
const cred = await navigator.credentials.get({
password: true,
mediation: 'optional'
});
if (cred) {
// User selected an account from the browser's account chooser
document.getElementById('username').value = cred.id;
document.getElementById('password').value = cred.password;
// Programmatically submit the form or send via fetch
document.getElementById('login-form').submit();
} else {
// User closed the account chooser. Let them type manually.
console.log('User cancelled the sign-in prompt.');
}
} catch (e) {
console.error('Error during user-initiated sign-in:', e);
}
});
ã¹ããã4ïŒç»é²ãšèªèšŒæ å ±ä¿åã®ãããŒ
æ°èŠãŠãŒã¶ãŒãæ£åžžã«ç»é²ããåŸããã©ãŠã¶ã«èªèšŒæ å ±ãä¿åããããä¿ããŸãã
const registrationForm = document.getElementById('registration-form');
registrationForm.addEventListener('submit', async (event) => {
event.preventDefault();
// Assume server-side registration is successful
// ...server logic here...
if (isCredManApiSupported) {
const form = event.target;
const cred = new PasswordCredential({
id: form.username.value,
password: form.password.value,
name: form.fullName.value
});
try {
await navigator.credentials.store(cred);
// Now redirect to the user's dashboard
window.location.href = '/dashboard';
} catch (e) {
console.warn('Credential could not be stored.', e);
// Still redirect, as registration was successful
window.location.href = '/dashboard';
}
} else {
// For unsupported browsers, just redirect
window.location.href = '/dashboard';
}
});
ã¹ããã5ïŒãµã€ã³ã¢ãŠããããŒ
æåŸã«ãã¯ãªãŒã³ãªãµã€ã³ã¢ãŠãããã»ã¹ã確ä¿ããŸãã
const signOutButton = document.getElementById('signout-button');
signOutButton.addEventListener('click', async () => {
// 1. Tell the server to end the session
await fetch('/api/logout', { method: 'POST' });
// 2. Prevent automatic sign-in on the next visit
if (isCredManApiSupported) {
try {
await navigator.credentials.preventSilentAccess();
} catch(e) {
console.error("Could not prevent silent access.", e)
}
}
// 3. Redirect the user
window.location.href = '/signed-out';
});
ãã§ãã¬ãŒã·ã§ã³IDãããã€ããŒãšã®çµ±å
APIã®æŽç·Žæ§ã¯ãã§ãã¬ãŒã·ã§ã³ãã°ã€ã³ã«ãåã³ãŸããè€éãªSDKããããã¢ãããŠã£ã³ããŠãçŽæ¥ç®¡çãã代ããã«ã`FederatedCredential`ã¿ã€ãã䜿çšã§ããŸãããµã€ãããµããŒãããIDãããã€ããŒãæå®ãããšããã©ãŠã¶ã¯ãããããã€ãã£ãUIã§è¡šç€ºã§ããŸãã
async function federatedSignIn() {
try {
const fedCred = await navigator.credentials.get({
federated: {
providers: ['https://accounts.google.com', 'https://www.facebook.com'],
// You can also include OpenID Connect parameters
// protocols: ['openidconnect'],
// clientId: 'your-client-id.apps.googleusercontent.com'
}
});
if (fedCred) {
// fedCred.id contains the user's unique ID from the provider
// fedCred.provider contains the origin of the provider (e.g., 'https://accounts.google.com')
// Send this token/ID to your backend to verify and create a session
await serverFederatedLogin(fedCred.id, fedCred.provider);
}
} catch (e) {
console.error('Federated sign-in failed:', e);
}
}
ãã®ã¢ãããŒãã¯ããã©ãŠã¶ã«ãŠãŒã¶ãŒã®ã¢ã€ãã³ãã£ãã£é¢ä¿ã«é¢ããããå€ãã®ã³ã³ããã¹ããäžããå°æ¥çã«ã¯ããå¹ççã§ä¿¡é Œæ§ã®é«ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«ã€ãªããå¯èœæ§ããããŸãã
æªæ¥ã¯ãã¹ã¯ãŒãã¬ã¹ïŒWebAuthnã®çµ±å
Credential Management APIã®çã®åã¯ãWebAuthnã®ã¯ã©ã€ã¢ã³ããµã€ãã®ãšã³ããªãã€ã³ããšããŠã®åœ¹å²ã«ãããŸãããã¹ã¯ãŒãã¬ã¹èªèšŒãå®è£ ããæºåãã§ãããšããå šãæ°ããAPIãåŠã¶å¿ èŠã¯ãããŸãããåã«`publicKey`ãªãã·ã§ã³ãä»ããŠ`create()`ãš`get()`ã䜿çšããã ãã§ãã
WebAuthnãããŒã¯ããµãŒããŒãšã®æå·çãªãã£ã¬ã³ãž-ã¬ã¹ãã³ã¹ã¡ã«ããºã ãå«ãããããè€éã§ãããããã³ããšã³ãã®ã€ã³ã¿ã©ã¯ã·ã§ã³ã¯ããã¹ã¯ãŒãã§ãã§ã«äœ¿çšããŠããã®ãšåãAPIãéããŠç®¡çãããŸãã
ç°¡ç¥åãããWebAuthnç»é²ã®äŸïŒ
// 1. Get a challenge from your server
const challenge = await fetch('/api/webauthn/register-challenge').then(r => r.json());
// 2. Use navigator.credentials.create() with publicKey options
const newPublicKeyCred = await navigator.credentials.create({
publicKey: challenge
});
// 3. Send the new credential back to the server for verification and storage
await fetch('/api/webauthn/register-verify', {
method: 'POST',
body: JSON.stringify(newPublicKeyCred)
});
仿¥CredMan APIã䜿çšããããšã§ãããå®å šã§ãã£ãã·ã³ã°èæ§ã®ããèªèšŒæ¹æ³ãžã®å¿ ç¶çãªç§»è¡ã«åããŠãã¢ããªã±ãŒã·ã§ã³ãèšèšããŠããããšã«ãªããŸãã
ãã©ãŠã¶ã®ãµããŒããšã»ãã¥ãªãã£ã«é¢ããèæ ®äºé
ãã©ãŠã¶äºææ§
Credential Management APIã¯ãChromeãFirefoxãEdgeãå«ãçŸä»£ã®ãã©ãŠã¶ã§åºããµããŒããããŠããŸããããããSafariã§ã®ãµããŒãã¯ãç¹ã«ç¹å®ã®æ©èœã«ãããŠããéå®çã§ããåžžã«Can I Use...ã®ãããªäºææ§ãªãœãŒã¹ã§ææ°æ å ±ã確èªããæšæºã®HTMLãã©ãŒã ãå®å šã«æ©èœããç¶ããããšã§ãã¢ããªã±ãŒã·ã§ã³ãåªé ã«æ©èœäœäžããããã«ããŠãã ããã
éèŠãªã»ãã¥ãªãã£ã®ãã¹ããã©ã¯ãã£ã¹
- HTTPSã¯å¿ é ïŒ æ©å¯æ å ±ãæ±ãå€ãã®çŸä»£ã®ãŠã§ãAPIãšåæ§ã«ãCredential Management APIã¯ã»ãã¥ã¢ãªã³ã³ããã¹ãã§ã®ã¿å©çšå¯èœã§ããããªãã®ãµã€ãã¯HTTPSã§æäŸãããªããã°ãªããŸããã
- ãµãŒããŒãµã€ãã®æ€èšŒã¯å¿ é ïŒ ãã®APIã¯ã¯ã©ã€ã¢ã³ããµã€ãã®å©äŸ¿æ§ã®ããã®ãã®ã§ãããŠãŒã¶ãŒããã¢ããªã±ãŒã·ã§ã³ãžèªèšŒæ å ±ãæž¡ãã®ãå©ããŸããããããæ€èšŒãããã®ã§ã¯ãããŸãããã¯ã©ã€ã¢ã³ãã絶察ã«ä¿¡çšããªãã§ãã ããããã¹ã¯ãŒãããŒã¹ã§ããããšæå·ããŒã¹ã§ããããšããã¹ãŠã®èªèšŒæ å ±ã¯ãã»ãã·ã§ã³ãä»äžãããåã«ããã¯ãšã³ãã§å®å šã«æ€èšŒãããªããã°ãªããŸããã
- ãŠãŒã¶ãŒã®æå³ãå°éããïŒ `mediation: 'silent'`ã責任ãæã£ãŠäœ¿çšããŠãã ãããããã¯ã»ãã·ã§ã³ã埩å ããããã®ãã®ã§ããããŠãŒã¶ãŒã远跡ããããã®ãã®ã§ã¯ãããŸãããåžžã«`preventSilentAccess()`ãåŒã³åºãå ç¢ãªãµã€ã³ã¢ãŠããããŒãšçµã¿åãããŠãã ããã
- `null`ãåªé ã«åŠçããïŒ `get()`ã®åŒã³åºãã`null`ã§è§£æ±ºãããããšã¯ãšã©ãŒã§ã¯ãããŸãããããã¯ãããŒã®æ£åžžãªéšåã§ããããŠãŒã¶ãŒãä¿åãããèªèšŒæ å ±ãæã£ãŠããªããããã©ãŠã¶ã®ããã³ããããã£ã³ã»ã«ããããšãæå³ããŸããUIã¯ã圌ããæåå ¥åã§ã·ãŒã ã¬ã¹ã«ç¶è¡ã§ããããã«ããå¿ èŠããããŸãã
çµè«
ããã³ããšã³ãCredential Management APIã¯ããŠã§ãã¢ããªã±ãŒã·ã§ã³ãèªèšŒãæ±ãæ¹æ³ã«ãããæ ¹æ¬çãªé²åã衚ããŠããŸããããã¯ç§ãã¡ããèãæ©æŠã®å€ããã©ãŒã ãããæšæºåãããå®å šã§ããŠãŒã¶ãŒäžå¿ã®ã¢ãã«ãžãšç§»è¡ãããŸããã¢ããªã±ãŒã·ã§ã³ãšãã©ãŠã¶ã®åŒ·åãªèªèšŒæ å ±ã¹ãã¢ãšã®éã®æ¶ãæ©ãšããŠæ©èœããããšã§ãã·ãŒã ã¬ã¹ãªã¯ã³ã¿ãããµã€ã³ã€ã³ãæŽç·Žããããã§ãã¬ãŒã·ã§ã³ãã°ã€ã³ããããŠWebAuthnã«ãããã¹ã¯ãŒãã¬ã¹ã®æªæ¥ãžã®æç¢ºãªéçãæäŸããããšãã§ããŸãã
ãã®APIãæ¡çšããããšã¯æŠç¥çãªæè³ã§ããããã¯ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããã³ã³ããŒãžã§ã³ããªãã³ã·ã§ã³ã«çŽæ¥åœ±é¿ãäžããå¯èœæ§ããããŸãããã£ãã·ã³ã°ã®ãããªäžè¬çãªè åšã«å¯Ÿããã»ãã¥ãªãã£æ å¢ã匷åããŸãããããŠãããã³ããšã³ãã®ã³ãŒããç°¡çŽ åããããä¿å®ããããå°æ¥æ§ã®ãããã®ã«ããŸãããŠãŒã¶ãŒã®ç¬¬äžå°è±¡ããã°ãã°ãã°ã€ã³ç»é¢ã§ããäžçã«ãããŠãCredential Management APIã¯ããã®å°è±¡ãããžãã£ãã§æ¥œãªãã®ã«ããããã«å¿ èŠãªããŒã«ãæäŸããŸãã